package com.company.bookstore.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.company.bookstore.common.constant.RequestConstant;
import com.company.bookstore.common.jwt.JwtUtil;
import com.company.bookstore.common.redis.RedisUtil;
import com.company.bookstore.common.result.MvcResult;
import com.company.bookstore.entities.user_admin_module.Admin;
import com.company.bookstore.entities.user_admin_module.User;
import com.company.bookstore.exception.user_admin_module.CustomException;
import com.company.bookstore.service.user_admin_module.AdminService;
import com.company.bookstore.service.user_admin_module.UserService;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JwtFilter
 *
 * 跳过public uri jwt 检测
 *
 * @blame Android Team
 */
@Slf4j
public class JwtFilter extends OncePerRequestFilter {
    public static final String PUBLIC_URI = "/public";
//    private final RedisUtil redisUtil;

    public JwtFilter(RedisUtil redisUtil) {
//        this.redisUtil = redisUtil;
    }
    @Resource
    UserService userService;
    @Resource
    AdminService adminService;

    /**
     *
     * 在{@link UsernamePasswordFilter} 后面
     *
     * {@link RequestConstant} HTTP_LOGIN_JWT_HEADER 进行jwt验证的条件，是http头部具有header声明
     *
     * 如果请求不包含token ， 则拒绝请求
     * 如果解析token 过期 ，则在解析的时候，代码会抛出异常
     * 检测到异常后，检擦
    * */
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        httpServletResponse.setContentType("application/json;utf-8");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");  // 允许跨域的地址为所有
        httpServletResponse.addHeader("Access-Control-Max-Age","3600");  // 非简单请求，只要第一次通过OPTIONS检查 在1小时之内不会在调用OPTIONS进行检测
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setHeader("Access-Control-Allow-Headers" ,"Origin, X-Requested-With, Content-Type, Accept,login_token");
        httpServletResponse.setHeader("Access-Control-Allow-Methods" ,"OPTIONS,GET,POST,PUT,DELETE");
        String token = httpServletRequest.getHeader(RequestConstant.HTTP_LOGIN_JWT_HEADER);
        String prefix = httpServletRequest.getRequestURI();
        if (prefix.startsWith(PUBLIC_URI)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            SecurityContextHolder.getContext()
                    .setAuthentication
                            (new UsernamePasswordAuthenticationToken("none", "none",AuthorityUtils.createAuthorityList("ROLE_NONE")));
            return;
        }
        logger.info("进行token判断************");
        if (token==null){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        try {
//          解析前端传来的token ，如果过期，非法签名，格式错误则直接返回错误
            JwtUtil.TokenMessage tokenMessage = JwtUtil.getTokenMessage(token);
//            assert tokenMessage.getUsername() !=null ;
//            String redisJwt = redisUtil.getJwt(tokenMessage.getUsername());
//            if (redisJwt == null){
//                logger.info("redisJws为空，用户未登录");
//                httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.builder().code(403).message("用户尚未登录，请登录").build()));
//                return;
//            }
//            与redis上的token 进行对比 redis 上的token总是最新的，对比成功则用户可信，对比不成功则不可信
//            if (!token.equals(redisJwt)){
//                logger.info("token不一致");
//                里面的权限字段在数据库中发生了更新，本地的token没有更新，所以不一致
//                httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.builder().code(403).message("token不一致").build()));
//                return;
//            }
            String role =tokenMessage.getRole();
            String name = tokenMessage.getUsername();

//            用户token
            if (role == null){
                role = "ROLE_NONE";
//                User u ;
//                u =(User)  userService.loadUserByUsername(name);
//                if (u.getEnable()==0||u.getDeleted()==1){
//                    throw new CustomException ("该账号已被冻结",480);
//                }
            }else {
//                Admin a ;
//                a =(Admin)  adminService.loadUserByUsername(name);
//                if (a.getDeleted()==1){
//                    throw new CustomException ("该账号已被冻结",480);
//                }
            }

            SecurityContextHolder.getContext()
                    .setAuthentication
                            (new UsernamePasswordAuthenticationToken(tokenMessage.getUsername(), "none",AuthorityUtils.createAuthorityList(role)));
            if (httpServletRequest.getRequestURI().startsWith(RequestConstant.HTTP_LOGIN_ADMIN_URI)||
                httpServletRequest.getRequestURI().startsWith(RequestConstant.HTTP_LOGIN_USER_URI)
                ){
                httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.LOGING_SUCCESS));
                return;
            }
            filterChain.doFilter(httpServletRequest,httpServletResponse);
        }catch (MalformedJwtException m ){
            logger.info("token解析异常");
            logger.info((JSON.toJSONString(MvcResult.builder().code(500).message("token解析异常").build())));
            httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.builder().code(500).message("token解析异常").build()));
        }catch (SignatureException s){
            log.info("密钥签名错误");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(MvcResult.builder().code(500).message("密钥签名错误，请重新登录").build()));
        }catch (ExpiredJwtException e){
            logger.info("该token已经过期");
//            JwtUtil.TokenMessage tokenMessage = JSONObject.parseObject(e.getClaims().getSubject(), JwtUtil.TokenMessage.class);
//            redisUtil.deleteJwt(tokenMessage.getUsername());
            httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.builder().code(444).message("该token已经过期,请重新登录").build()));
        }
//        catch (CustomException c){
//            logger.info("账号已被冻结");
//            httpServletResponse.getWriter().write(JSON.toJSONString(MvcResult.builder().code(c.getCode()).message(c.getMessage()).build()));
//        }

    }
}
